﻿//*** Guidance generated code ***//
using System;
using System.Collections.Generic;
using System.Linq;

using StructureMap.Configuration.DSL;
using StructureMap.Graph;

using ProjectBase.Core;
using ProjectBase.Core.Dao;
using ProjectBase.Data.NH;

using $prjsn$.Common.Data;
using $prjsn$.Common.Validation;

namespace $safeprojectname$.IoC
{
    [CLSCompliant(false)]
    public class ProxyConvention : DefaultConventionScanner
    {
        public static string ProfileName { get; set; }

        public override void Process(Type type, Registry registry)
        {
            var profileName = ProfileName;

            foreach (var inter in type.GetInterfaces()
                .Where(i => i.GetInterfaces().Any(t => t.IsEquivalentTo(typeof(IService))))
                .Where(i => !i.IsEquivalentTo(typeof(IFacade))
                    && !i.IsEquivalentTo(typeof(ICoreModel))
                    && !i.IsEquivalentTo(typeof(IDao))
                    && !i.IsEquivalentTo(typeof(IApiService))
                    && !i.IsEquivalentTo(typeof(ICoreController<>))))
            {
                if (!MapAsSingleton(inter, type, registry))
                {
                    // Interface registration
                    var setting = registry
                        .For(inter)
                        .HybridHttpOrThreadLocalScoped();
                    if (type.HasType<IHaveSessionFactoryName>())
                    {
                        setting.OnCreation(obj =>
                        {
                            var dao = obj as IHaveSessionFactoryName;
                            dao.SessionFactoryName = profileName + "Factory";
                        });
                    }
                    setting.Use(new ProxyInstance(type));
                }
            }

            MapAncestors(type, registry);
        }

        private static readonly IList<Type> CanBeSingleton = new List<Type>
        {
            typeof (IResetCacheFacade),
            typeof (INHSessionHandler),
            typeof (IXmlSessionHandler),
            typeof (IDbSessionHandler),
        };

        private static readonly IList<Type> CanBeGenericSingleton = new List<Type>
        {
            typeof (IApplyFilterRestrictions<,>),
            typeof (IEntityValidator<,>),
            typeof (IMetaDataProvider<,>),
            typeof (IHaveMappingInfo<>),
        };

        private static bool MapAsSingleton(Type inter, Type type, Registry registry)
        {
            var isOrExtendsSingleton = CanBeSingleton
                .Any(i => inter.IsEquivalentTo(i));

            var isOrExtensGenericSingleton = CanBeGenericSingleton
                .Any(i => inter.IsGenericType && inter.GetGenericTypeDefinition().IsEquivalentTo(i));

            if (isOrExtendsSingleton || isOrExtensGenericSingleton)
            {
                registry
                    .For(inter)
                    .Singleton()
                    .Use(new ProxyInstance(type));
                return true;
            }
            return false;
        }

        private static void MapAncestors(Type type, Registry registry)
        {
            // the implementor itself
            registry
                .For(type)
                .Use(type);

            // Base types to be replaced by child
            var currentType = type;

            // only if base is still IService
            var isBasePluginType =
                currentType.BaseType.Is()
                && currentType.BaseType.HasType(typeof(IService));

            while (isBasePluginType)
            {
                // abstract is out of scope
                if (!currentType.BaseType.IsAbstract)
                {
                    registry
                        .For(currentType.BaseType)
                        .Use(currentType);
                }

                currentType = currentType.BaseType;

                isBasePluginType =
                    currentType.BaseType.Is()
                    && currentType.BaseType.HasType(typeof(IService));
            }
        }
    }
}